package com.realife.eson.common.util.information;

import com.realife.eson.common.asserts.AssertNP;
import jodd.time.TimeUtil;
import org.apache.commons.lang3.time.FastDateFormat;
import org.joda.time.*;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.util.*;


/**
 * @version V1.0
 * @author: guangcheng
 * @date: 2022/5/26 10:47
 * @description:
 */
public class MeTimeUtil {
    public static String pattern0 = "yyyy-MM-dd HH:mm:ss:SSS";
    public static String pattern1 = "yyyy/MM/dd HH:mm:ss";
    public static String pattern2 = "yyyy-MM-dd HH:mm:ss";
    public static String pattern3 = "yyyy年MM月dd日 HH时:mm分:ss秒";

    private MeTimeUtil() {
    }


    public static String getTimeStampStr(Long timestamp, String pattern) {
        return FastDateFormat.getInstance(pattern).format(timestamp);
    }

    /**
     * getStringByDateTimeTZ
     *
     * @param dateTimeTZ 2022-05-25T02:22:50Z
     * @param pattern    yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static synchronized String getStringByDateTimeTZ(String dateTimeTZ, String pattern) {
        //
        List<Integer> ts = parseDateTimeStrTZ(dateTimeTZ);
        int size0 = ts.size();
        if (AssertNP.legalParams(ts) && (ts.size() < 6)) {
            for (int i = 0; i < (6 - size0); i++) {
                ts.add(size0 + i, 0);
            }
            Integer month = ts.get(1);
            if (AssertNP.atLeastOneTrue(month > 12, month < 1)) {
                ts.set(1, 1);
            }
            if (ts.get(2) == 0) {
                ts.set(2, 1);
            }
        }
        if (ts.size() > 6 || !AssertNP.legalParams(ts)) {
            return "1949年10月1日 00时:00分:00秒";
        }
        Date date = TimeUtil.toDate(LocalDateTime.of(ts.get(0), Month.of(ts.get(1)), ts.get(2),
                ts.get(3), ts.get(4), ts.get(5)));
        //
        String dateString = MeDateUtil.getDateString(date, pattern);
        return dateString;
    }

    /**
     * 2022-05-25T02:22:50Z
     *
     * @param dateTimeStr
     * @return
     */
    private static List<Integer> parseDateTimeStrTZ(String dateTimeStr) {
        String strT = dateTimeStr.replaceAll("T", " ").replaceAll("Z", "").replaceAll("-", " ")
                .replaceAll(":", " ");

        List<Integer> myList = new ArrayList<>();
        String[] splitStr = strT.split(" ");
        if (AssertNP.legalParams(splitStr)) {
            for (int i = 0; i < splitStr.length; i++) {
                int anInt = Integer.parseInt(splitStr[i]);
                myList.add(anInt);
            }
        }
        return myList;
    }


    /**
     * 时间差换算为 日,时,分,秒,毫秒表示
     *
     * @param str1 yyyy-MM-dd HH:mm:ss:SSS
     * @param str2 yyyy-MM-dd HH:mm:ss:SSS
     * @return
     */
    public static synchronized Map<String, Long> getDistanceTime(String str1, String str2, boolean isMill) {
        Map<String, Long> map = new HashMap<>();
        SimpleDateFormat df = null;
        if (isMill) {
            df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        } else {
            df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
        Date one;
        Date two;
        long day = 0;//天数差
        long hour = 0;//小时数差
        long min = 0;//分钟数差
        long second = 0;//秒数差
        long mill = 0;//毫秒数差
        long diff = 0;//总计毫秒差
        try {
            final Calendar c = Calendar.getInstance();
            c.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
            one = df.parse(str1);
            c.setTime(one);
            two = df.parse(str2);
            long time1 = one.getTime();
            long time2 = two.getTime();
            diff = time2 - time1;
            day = diff / (24 * 60 * 60 * 1000);
            hour = (diff / (60 * 60 * 1000) - day * 24);
            min = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60);
            second = diff / 1000 - min * 60 - hour * 3600 - day * 86400;
            mill = diff - second * 1000 - min * 60 * 1000 - hour * 3600 * 1000 - day * 86400 * 1000;
            map.put("day", day);
            map.put("hour", hour);
            map.put("min", min);
            map.put("second", second);
            map.put("mill", mill);
        } catch (Exception e) {

        }
        return map;
    }

    /**
     * @param map
     * @return
     */
    public static long getMillsByMap5(Map<String, Long> map) {
        Long day = map.get("day");
        Long hour = map.get("hour");
        Long min = map.get("min");
        Long second = map.get("second");
        Long mill = map.get("mill");
        return day * 86400 * 1000 + hour * 3600 * 1000 + min * 60 * 1000 + second * 1000 + mill;
    }


    /**
     * @param timeStr yyyy-MM-dd HH:mm:ss.SSS    yyyy-MM-dd HH:mm:ss
     * @return yyyy-MM-dd HH:mm:ss:SSS
     */
    public static String getTimeStampStr(String timeStr) {
        Timestamp timestamp = Timestamp.valueOf(timeStr);
        return getTimeStampStr(timestamp);
    }


    /**
     * @param longNum longTime
     * @return
     */
    public static String getTimeStampStr(long longNum) {
        Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now());
        timestamp.setTime(longNum);
        return getTimeStampStr(timestamp);
    }


    /**
     * @param timestamp timeStamp
     * @return
     */
    public static String getTimeStampStr(Timestamp timestamp) {
        return timestamp.toString().replaceAll("\\.", "\\:");
    }


    public static LocalDateTime getLocalDateTime(long longNum) {
        return TimeUtil.fromMilliseconds(longNum);
    }

    public static String getTimeStampStr(LocalDateTime localDateTime) {
        Timestamp timestamp = Timestamp.valueOf(localDateTime);
        return getTimeStampStr(timestamp);
    }


    public static Timestamp getTimeStamp(LocalDateTime localDateTime) {
        return Timestamp.valueOf(localDateTime);
    }

    public static Timestamp getTimeStampBySet(long longNum) {
        Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now());
        timestamp.setTime(longNum);
        return timestamp;
    }

    public static Timestamp getTimeStampByNew(long longNum) {
        return new Timestamp(longNum);
    }

    /**
     * @param timeStr yyyy-MM-dd HH:mm:ss.SSS    yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static Timestamp getTimeStamp(String timeStr) {
        return Timestamp.valueOf(timeStr);
    }

    /**
     * @param year
     * @param month
     * @param dayOfMonth
     * @param hour
     * @param minute
     * @param second
     * @param nanoOfSecond
     * @return
     */
    public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) {
        LocalDate date = LocalDate.of(year, month, dayOfMonth);
        LocalTime time = LocalTime.of(hour, minute, second, nanoOfSecond);
        return LocalDateTime.of(date, time);
    }


    public static DateTime getDateTime() {
        return new DateTime();
    }

    public static DateTime getDateTime(Date date) {
        return new DateTime(date);
    }

    public static DateTime getDateTime(int year, int month, int day, int hour, int min, int second, int mill) {
        return new DateTime(year, month, day, hour, min, second, mill);
    }

    /**
     * @param timeStr 2022-05-21   2022-05-21T10:00:15
     * @return
     */
    public static DateTime getDateTime(String timeStr) {
        return new DateTime(timeStr);
    }


    public static org.joda.time.LocalDate getLocalDate(int year, int month, int day) {
        return new org.joda.time.LocalDate(year, month, day);
    }

    public static org.joda.time.LocalTime getLocalTime(int hour, int min, int second, int mill) {
        return new org.joda.time.LocalTime(hour, min, second, mill);
    }

    public static Map<String, Integer> getDateTimeMap(DateTime dateTime) {
        Map<String, Integer> map = new HashMap<>();
        map.put("year", dateTime.getYear());
        map.put("month", dateTime.getMonthOfYear());
        map.put("dayOfMonth", dateTime.getDayOfMonth());
        map.put("dayOfWeek", dateTime.getDayOfWeek());
        map.put("dayOfYear", dateTime.getDayOfYear());
        map.put("hour", dateTime.getHourOfDay());
        map.put("minOfDay", dateTime.getMinuteOfDay());
        map.put("minOfHour", dateTime.getMinuteOfHour());
        map.put("secOfDay", dateTime.getSecondOfDay());
        map.put("secOfMinute", dateTime.getSecondOfMinute());
        map.put("millOfSecond", dateTime.getMillisOfSecond());
        map.put("millOfDay", dateTime.getMillisOfDay());
        return map;
    }


    public static Date getDateByMills(DateTime dateTime) {
        return new Date(dateTime.getMillis());
    }

    public static Date getDate(DateTime dateTime) {
        return dateTime.toDate();
    }

    public static Calendar getCalendar(DateTime dateTime) {
        Calendar instance = Calendar.getInstance();
        instance.setTimeInMillis(dateTime.getMillis());
        return instance;
    }

    public static Calendar getCalendarBYToCalendar(DateTime dateTime) {
        return dateTime.toCalendar(Locale.getDefault());
    }


    public static DateTime minusDays(DateTime dateTime, int days) {
        return dateTime.minusDays(days);
    }

    public static DateTime plusDays(DateTime dateTime, int days) {
        return dateTime.plusDays(days);
    }

    public static DateTime minusMonth(DateTime dateTime, int months) {
        return dateTime.minusMonths(months);
    }

    public static DateTime plusMonths(DateTime dateTime, int months) {
        return dateTime.plusMonths(months);
    }

    public static DateTime minusYears(DateTime dateTime, int years) {
        return dateTime.minusYears(years);
    }

    public static DateTime plusYears(DateTime dateTime, int years) {
        return dateTime.plusYears(years);
    }


    public static DateTime monthEnd(DateTime dateTime) {
        return dateTime.dayOfMonth().withMaximumValue();
    }

    public static DateTime plusDaysWithMonday(DateTime dateTime, int days) {
        return dateTime.plusDays(days).dayOfWeek().withMinimumValue();
    }


    /**
     * @param zone Asia/Shanghai  Asia/Tokyo
     */
    public static void setDefaultTimeZone(String zone) {
        DateTimeZone.setDefault(DateTimeZone.forID(zone));
    }

    /**
     * @param zone Asia/Shanghai  Europe/London
     * @return
     */
    public static DateTime getDateTimeWithZone(String zone) {
        return new DateTime(DateTimeZone.forID(zone));
    }

    public static long getMillsDistanceForDateTime(DateTime d1, DateTime d2) {
        Duration duration = new Duration(d1, d2);
        return duration.getMillis();
    }

    public static int getDaysDistanceForDateTime(DateTime d1, DateTime d2) {
        Period period = new Period(d1, d2, PeriodType.days());
        return period.getDays();
    }

    public static boolean isContains(DateTime d1, DateTime d2, String timeStr) {
        Interval interval = new Interval(d1, d2);
        return interval.contains(new DateTime(timeStr));
    }


    public static boolean isAfter(DateTime d1, DateTime d2) {
//        d1.isBefore(d2);
//        d1.isEqual(d2);
//        d1.isAfterNow();
//        d1.isBeforeNow();
//        d1.isEqualNow();
        return d1.isAfter(d2);
    }


    /**
     * yyyy/MM/dd hh:mm:ss.SSSa          2022/05/29 01:37:06.973下午
     * yyyy-MM-dd HH:mm:ss               2022-05-29 13:37:35
     * yyyy-MM-dd HH:mm:ss:SSS           2022-05-29 16:24:00:686
     * EEEE dd MMMM, yyyy HH:mm:ssa      星期日 29 五月, 2022 13:36:34下午
     * yyyy/MM/dd HH:mm:ss ZZZZ          2022/05/29 13:38:24 Asia/Shanghai
     * yyyy/MM/dd HH:mm:ss Z             2022/05/29 13:39:01 +0800
     *
     * @param dateTime
     * @param format
     * @return
     */
    public static String formatDatetime(DateTime dateTime, String format) {
        return dateTime.toString(format);
    }


    /**
     *
     * @param timestamp long
     * @param pattern yyyy-MM-dd HH:mm:ss:SSS
     * @return
     */
    public static String format(Long timestamp, String pattern) {
        return FastDateFormat.getInstance(pattern).format(timestamp);
    }




    public static void main(String[] args) {

        String format = format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss:SSS");
        System.out.println("format =\n" + format);// 2022-06-13 16:35:46:018


        String s = formatDatetime(getDateTime(), "yyyy-MM-dd HH:mm:ss:SSS");
        System.out.println("s =\n" + s);

        String stringByDateTimeTZ = getStringByDateTimeTZ("2022-05-25T02:22:50Z", pattern2);
        System.out.println("stringByDateTimeTZ =\n" + stringByDateTimeTZ);
        String timeStampStr3 = getTimeStampStr(stringByDateTimeTZ);
        System.out.println("timeStampStr3 =\n" + timeStampStr3);


        LocalDateTime localDateTime = getLocalDateTime(16030006986L);
        String timeStampStr = getTimeStampStr(localDateTime);
        System.out.println("timeStampStr =\n" + timeStampStr);

        System.out.println("==============================================================================\n");

        String timeStampStr1 = getTimeStampStr("2022-05-25 02:22:50.102");
        System.out.println("timeStampStr1 =\n" + timeStampStr1);

        System.out.println("==============================================================================\n");
        String timeStampStr2 = getTimeStampStr(16030006986L);
        System.out.println("timeStampStr2 =\n" + timeStampStr2);


        LocalDateTime of = of(2001, 2, 7, 9, 10, 15, 999000000);
        String timeStampStr4 = getTimeStampStr(of);
        System.out.println("timeStampStr4 =\n" + timeStampStr4);


        DateTime dateTime = getDateTime();
        Map<String, Integer> dateTimeMap = getDateTimeMap(dateTime);
        System.out.println("dateTimeMap =\n" + dateTimeMap);

        DateTime dateTime1 = plusDaysWithMonday(getDateTime(), 100);
        Map<String, Integer> dateTimeMap1 = getDateTimeMap(dateTime1);
        System.out.println("dateTimeMap1 =\n" + dateTimeMap1);

        Map<String, Long> distanceTime = getDistanceTime("2013-06-7 06:12:50:992", "2022-05-25 02:22:50:102", true);
        long millsByMap5 = getMillsByMap5(distanceTime);
        System.out.println("millsByMap5 =\n" + millsByMap5);
        long day = millsByMap5 / (1000 * 86400);
        System.out.println("day =\n" + day);


        String timeStampStr5 = getTimeStampStr(System.currentTimeMillis(), pattern2);
        System.out.println("timeStampStr5 =\n" + timeStampStr5);
    }

}

